/*
 *  Filename:lsv_volume.c
 *  Description:
 *
 *  Created on: 2017年3月2日
 *  Author: gj
 */

#include "config.h"

#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>

#define DBG_SUBSYS S_LIBSTORAGE

#include "lsv.h"
#include "lsv_conf.h"
#include "lsv_volume.h"
#include "lsv_help.h"

int chunk_pool_init(chunk_pool **_pool, lsv_volume_proto_t *lsv_info, int capacity) {
        int ret;

        *_pool = NULL;

        chunk_pool *pool;

        ret = ymalloc((void **)&pool, sizeof(chunk_pool));
        if (unlikely(ret)) {
                GOTO(err_ret, ret);
        }

        pool->lsv_info = lsv_info;
        pool->capacity = capacity;
        pool->count = capacity;
        lsv_rwlock_init(&pool->lock);

        ret = ymalloc((void **)&pool->chunk_ids, sizeof(uint32_t)*capacity);
        if (unlikely(ret)) {
                GOTO(err_ret, ret);
        }

        for (int i=0; i < capacity; i++) {
                pool->chunk_ids[i] = 0;
        }

        *_pool = pool;
        return 0;
err_ret:
        return ret;
}

int __load_chunk_pool(chunk_pool *pool) {
        int ret;

        struct timeval t1, t2;
        _gettimeofday(&t1, NULL);

        ret = lsv_volume_chunk_malloc_batch(pool->lsv_info, LSV_WBUFFER_STORAGE_TYPE,
                                            pool->capacity, pool->chunk_ids);
        if (unlikely(ret)) {
                GOTO(err_ret, ret);
        }

        pool->count = 0;

        _gettimeofday(&t2, NULL);
        int64_t used = _time_used(&t1, &t2);
        DERROR("used %llu\n", (LLU)used);

        return 0;
err_ret:
        return ret;
}

int chunk_pool_select(chunk_pool *pool, uint32_t *chunk_id) {
        int ret;

        if (pool->count >= pool->capacity) {
                lsv_wrlock(&pool->lock);
                if (pool->count >= pool->capacity) {
                        ret = __load_chunk_pool(pool);
                        if (unlikely(ret)) {
                                GOTO(err_ret, ret);
                        }
                }
                lsv_unlock(&pool->lock);
        }

        YASSERT(pool->count < pool->capacity);
        *chunk_id = pool->chunk_ids[pool->count++];
        YASSERT(*chunk_id != 0);

        return 0;
err_ret:
        return ret;
}
